package cn.nexd.location.core;


import android.text.TextUtils;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import cn.nexd.location.utils.JsonParseUtil;


/**
 * 核心的定位算法
 * Created by admin on 15/8/27.
 */
public final class NexdIndoorLocationAlgorithm {
    static {
        System.loadLibrary("location_engine");
    }

    private NexdIndoorWifiExtractor wifiExtractor = new NexdIndoorWifiExtractor();
    //    private NexdIndoorFloorDetection floorDetection = new NexdIndoorFloorDetection();
    private long currentBuildingId = -1L;
    private long currentFloorId = -1L;
    private String[] wifilist;

    private NexdIndoorLocationAlgorithm() {

    }

    public static NexdIndoorLocationAlgorithm getInstance() {
        return ClassHolder.INDOOR_LOCATION_ALGORITHM;
    }

    public void setCurrentBuildingId(long currentBuildingId) {

        this.currentBuildingId = currentBuildingId;
    }

    public void setCurrentFloorId(long currentFloorId) {
        this.currentFloorId = currentFloorId;
    }

    //初始化定位用的配置文件
    public void initIndoorLocationConfig(String optparam, String wp, String wifilist) throws IOException {
        CoreFileLoader cf = new CoreFileLoader();
        cf.loadWifiList(new FileInputStream(wifilist));
        this.initIndoorLocationConfig(optparam, wp, cf.wifi_list);
    }

    //初始化切层用的定位文件
    //    public void initIndoorFloorDetectionConfig(InputStream mean, InputStream var, InputStream weight, InputStream wifilist) throws IOException {
    //        floorDetection.loadConfiguration(mean, var, weight, wifilist);
    //
    //    }

    public void initIndoorFloorDetectionConfig(InputStream readme, InputStream modelInputStream, InputStream wifilist) throws IOException {
        GetFloorId.setLocationConfig(readme, modelInputStream, wifilist);
    }

    private void initIndoorLocationConfig(String optpath, String pospath, String[] wifilist) {
        this.wifilist = wifilist;
        CoreJNIUtil.freeEngine();
        CoreJNIUtil.initEngine(pospath, optpath);
        //        this.wifiExtractor.setWifiList(wifilist);
    }


    // 定时用来定位,不使用切层数据
    public JSONObject locationIndoorPosition(String wifi, long buildingId, long floorId) {
        //        return _outputFormat(locationIndoorPosition(wifi , floorId) , floorId)
        try {
            double[] input_array = wifiExtractor.extractWifi(wifilist, wifi);
            double[] locationPosition = CoreJNIUtil.locatePostion(input_array);
            JSONObject formatLocationResult = formatLocationResult(locationPosition, String.valueOf(floorId), buildingId);
            return formatLocationResult;

        } catch (JSONException e) {
            return null;
        }
    }

    public JSONObject location(String wifi, long buildingId) {
        try {
            return formatLocationResult(CoreJNIUtil.locatePostion(wifiExtractor.extractWifi(wifilist, wifi)), locationFloorDetection(wifi), buildingId);
        } catch (JSONException e) {
            return null;
        }
    }

    // 只用来计算切层数据,并不计算定位点.
    public String locationFloorDetection(String wifi) {
        String floor_id = "";

        Map<String, Object> map = new JsonParseUtil().parse(wifi);
        Map<String, Double> wifiMap = new HashMap<String, Double>();
        for (Map.Entry entry : map.entrySet()) {
            // edit by wangxu  2016-03-18 11:17
            wifiMap.put((String) entry.getKey(), parseWifiSign((String) entry.getValue()));
        }
        floor_id = GetFloorId.getFloor(wifiMap);
        //        try {
        //            floor_id = floorDetection.floorDetection(wifi, wifiExtractor);

        //        } catch (JSONException e) {
        //            floor_id = "-1";
        //        }
        return floor_id;
    }



    private double parseWifiSign (String wifiSign) {
        double parseWifiSing = Double.parseDouble(wifiSign) + 100d;
        if (parseWifiSing < 20) {
            parseWifiSing = 0.0d;
        }
        return parseWifiSing;
    }
    private JSONObject formatLocationResult(double[] res, String floorId, long buildingId) throws JSONException {
        JSONObject jsonObject = new JSONObject();
        if (TextUtils.isEmpty(floorId)) {
            // floorId == null or ""
            jsonObject.put("floor_id", -1);
        } else {
            jsonObject.put("floor_id", Long.parseLong(floorId));
        }

        jsonObject.put("building_id", buildingId);
        jsonObject.put("x", res[0]);
        jsonObject.put("y", res[1]);

        return jsonObject;
    }


    public long getCurrentBuildingId() {
        return currentBuildingId;
    }

    public long getCurrentFloorId() {
        return currentFloorId;
    }

    public void freeLocationEngineForCurrentBuildingId() {
        this.currentBuildingId = -1L;
    }

    public void freeLocationEngineForCurrentFloorId() {
        this.currentFloorId = -1L;
    }


    private static final class ClassHolder {
        public static final NexdIndoorLocationAlgorithm INDOOR_LOCATION_ALGORITHM = new NexdIndoorLocationAlgorithm();
    }
}
